package com.zzh.demo.feign.config;

import com.zzh.demo.core.exception.FeignException;
import feign.Client;
import feign.Feign;
import feign.Response;
import feign.Retryer;
import feign.codec.Encoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.netflix.feign.ribbon.CachingSpringLoadBalancerFactory;
import org.springframework.cloud.netflix.feign.ribbon.LoadBalancerFeignClient;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.servlet.http.HttpServletRequest;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import static com.zzh.demo.core.common.constants.Constants.HEADER_COOKIE;


/**
 * description： FeignClient配置类<br>
 * createTime: 2018/1/415:31 <br>
 *
 * @author zzh
 */
@Component
@Configuration
@Slf4j
public class Provider2FeignConfiguration {

//    @Value("${feign.provider2.user}")
//    private String user;

//    @Value("${feign.provider2.password}")
//    private String password;


    @Bean
    @Primary
    @Scope("prototype")
    public Encoder multipartFormEncoder() {
        //自定义请求编码器，扩展自feign-form库，支持多文件上传，并同时提交表单
        return new FeignSpringFormEncoder();
    }


    @Bean
    public feign.Logger.Level multipartLoggerLevel() {
        //配置feign的日志级别，配合配置文件设置才能生效
        return feign.Logger.Level.FULL;
    }


    @Bean
    @ConditionalOnMissingBean
    public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
                              SpringClientFactory clientFactory) throws NoSuchAlgorithmException, KeyManagementException {
        //配置feign请求，忽略证书验证
        SSLContext ctx = SSLContext.getInstance("SSL");
        X509TrustManager tm = new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
            }


            @Override
            public void checkServerTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
            }


            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        ctx.init(null, new TrustManager[]{tm}, null);
        return new LoadBalancerFeignClient(new Client.Default(ctx.getSocketFactory(),
                new HostnameVerifier() {
                    public boolean verify(String hostname, SSLSession sslSession) {
                        return true;
                    }
                }),
                cachingFactory, clientFactory);
    }


    @Bean
    public Feign.Builder feignBuilder() throws Exception {

        return Feign.builder()
                //注册异常解码器
                .errorDecoder(new feign.codec.ErrorDecoder() {
                    @Override
                    public Exception decode(String methodKey, Response response) {
                        return new FeignException(response.body().toString());
                    }
                })
                //带着请求cookie去请求接口，以维持session信息
                .requestInterceptor((requestTemplate) -> {
                        try {
                            RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
                            HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
                            requestTemplate.header(HEADER_COOKIE, request.getHeader(HEADER_COOKIE));

                        } catch (Exception e) {
                            log.info("初始化权限数据");
                        }
                    })
                //带basic认证头
//                .requestInterceptor(new BasicAuthRequestInterceptor(user, password))
                ;
    }

    //禁止Feign的重试，默认重试5次
    @Bean
    Retryer feignRetryer() {
        return Retryer.NEVER_RETRY;
    }
    //超时时间已经在配置文件里进行了配置，所以不需要再注入了
    //设置Feign连接超时时间和读取超时时间，默认为10秒，60秒
//    @Bean
//    Request.Options feignOptions() {
//        return new Request.Options(/**connectTimeoutMillis**/1 * 1000, /** readTimeoutMillis **/1 * 1000);
//    }
}